package library.net.retrofit.callback;


import java.io.File;
import java.io.RandomAccessFile;
import java.lang.reflect.Type;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Objects;

import io.reactivex.annotations.NonNull;
import library.net.retrofit.entity.FileEntity;
import library.net.retrofit.exception.RxException;
import library.net.retrofit.exception.RxExceptionHandler;
import library.net.retrofit.response.RxProgressResponseBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;

/**
 * @author Created by qiang.hou on 2017/12/18.
 * @version 1.0
 */
public abstract class RxFileCallback extends RxAbsCallback<File> {

    /**
     * 读写缓存大小
     */
    private static final int BLOCK_SIZE = 1024;

    /**
     * 文件实体
     */
    private FileEntity fileEntity = null;

    public RxFileCallback() {
    }

    public RxFileCallback(FileEntity fileEntity) {
        this.fileEntity = fileEntity;
    }

    @Override
    public void onResponse(@NonNull Call<ResponseBody> call, Response<ResponseBody> response) {
        if (null == fileEntity) {
            fileEntity = new FileEntity();
        }
        fileEntity.initFromSharedPre(call.request().url().toString());
        if (null == response.headers() || response.headers().get("Content-Range") == null
                || Objects.requireNonNull(response.headers().get("Content-Range")).length() == 0) {
            // 返回的没有Content-Range 不支持断点下载 需要重新下载
            fileEntity.completedBytes = 0L;
        }
        super.onResponse(call, response);
    }

    @Override
    public File transform(ResponseBody responseBody, Type type) throws Exception {
        if (null == responseBody) {
            return null;
        }

        if (null == fileEntity.destFileDir || fileEntity.destFileDir.equals("")) {
            onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                    RxExceptionHandler.ERROR.INVALID_SAVING_PATH, "文件保存路径不存在！")));
            return null;
        }

        if (!makeFileDir(fileEntity.destFileDir)) {
            onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                    RxExceptionHandler.ERROR.INVALID_SAVING_PATH, "文件保存路径不存在！")));
            return null;
        }

        String saveFilePath = FileEntity.initSavePath(
                fileEntity, Objects.requireNonNull(responseBody.contentType()).toString());
        final File saveFile = new File(saveFilePath);
        if (!saveFile.exists()) {
            if (!saveFile.createNewFile()) {
                onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                        RxExceptionHandler.ERROR.INVALID_SAVING_FILE, "文件保存失败！")));
            }
        }

        final RxProgressResponseBody rxProgressResponseBody = new RxProgressResponseBody(responseBody, fileEntity, this);
        RandomAccessFile randomAccessFile = new RandomAccessFile(saveFile, "rwd");
        FileChannel channelOut = randomAccessFile.getChannel();
        MappedByteBuffer mappedBuffer = channelOut.map(FileChannel.MapMode.READ_WRITE,
                fileEntity.completedBytes, fileEntity.totalBytes - fileEntity.completedBytes);
        try {
            int everyLength;
            byte[] buffer = new byte[BLOCK_SIZE];

            while ((everyLength = rxProgressResponseBody.byteStream().read(buffer)) != -1) {
                mappedBuffer.put(buffer, 0, everyLength);
            }
        } catch (Exception exception) {
            onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                    RxExceptionHandler.ERROR.INVALID_SAVING_FILE, "文件保存失败！")));
        } finally {
            fileEntity.commitToSharedPre(fileEntity.url);
            try {
                rxProgressResponseBody.byteStream().close();
                channelOut.close();
                randomAccessFile.close();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        return saveFile;
    }

    /**
     * 创建文件本地目录
     *
     * @return boolean
     */
    private boolean makeFileDir(String fileDir) {
        /* make directory */
        File dir = new File(fileDir);
        /* parent dir is exists? try to create parent dir */
        if (!dir.getParentFile().exists()) {
            if (!dir.getParentFile().mkdirs()) {
                onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                        RxExceptionHandler.ERROR.INVALID_SAVING_PATH, "文件保存路径不存在！")));
                return false;
            }
        }
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                        RxExceptionHandler.ERROR.INVALID_SAVING_PATH, "文件保存路径不存在！")));
                return false;
            }
        }
        if (!dir.exists()) {
            onError(getClass().getSimpleName(), RxExceptionHandler.handleException(new RxException(null,
                    RxExceptionHandler.ERROR.INVALID_SAVING_PATH, "文件保存路径不存在！")));
            return false;
        }
        return true;
    }
}
